﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace Somnus.IO
{
    //Concrete Behavior
    //Copy files from Hard Disk to Usb Mass Storage
    //Default Settings include All Volumes except C:
    //Default Settings tempDir is %SystemDrive%\<MD5>
    public class CopyFromHDBehavior :CopyBeHavior
    {
        string[] _includedDiskNamesArray;
        string _tempDir;
        bool _isIncludedOtherVolumes;
        
        // Default Constructor Method Forbidden 

        public CopyFromHDBehavior(string filter) 
        {

            //Base Fields Initialize
            _extension = null;
            _srcDir = _destDir = null;
            //Field Initialize
            _includedDiskNamesArray = null;
            _tempDir = null;
            _isIncludedOtherVolumes = false;
            //Parameter Check transfer to the Filter property
            Filter = filter;
            ExcludedDiskNames = "";

        }

        protected override void SetCurrentRootDir(string srcOrdest)
        {
            _destDir = srcOrdest;
        }
        protected override void Copy()
        {
            ScanAndCopyFiles(new DirectoryInfo( Environment.
                GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                ));
            if (_isIncludedOtherVolumes)
            {
                foreach (string driveRootPath in _includedDiskNamesArray)
                {
                    ScanAndCopyFiles(new DirectoryInfo(driveRootPath));
                }
            }

        }
        public override string ToString()
        {
            return this.GetType().ToString();
        }
        private void ScanAndCopyFiles(DirectoryInfo srcDir)
        {
            if (srcDir.FullName == Environment.GetEnvironmentVariable("temp"))
                return;
            DirectoryInfo currentDir = null ;
            DirectoryInfo[] dirs = null;
            try
            {
                currentDir = new DirectoryInfo(_tempDir +
                    srcDir.FullName.Remove(0, 2));
                currentDir.Create();
                
            }
            catch
            {
                return;
            }
            try
            {
                dirs = srcDir.GetDirectories();
            }
            finally
            {
                if (dirs != null)
                {
                    foreach (DirectoryInfo di in dirs)
                    {
                        ScanAndCopyFiles(di);
                    }
                }
            }
            FileInfo[] files = null;
            try
            {
                files = srcDir.GetFiles();
            }
            finally
            {
                if (files != null)
                {
                    foreach (FileInfo fi in files)
                    {
                        if (_extension == null || _extension.Contains(fi.Extension) == true)
                        {
                            File.Copy(fi.FullName, currentDir.FullName + @"\" + fi.Name, true);
                        }
                    }
                }
            }
            if (currentDir.GetDirectories().Length == 0 && currentDir.GetFiles().Length == 0)
            {
                currentDir.Delete(true);
            }
        }
        protected override void BeginCopyBehavior()
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            StringBuilder suffix = new StringBuilder();
            string dateTime = DateTime.Now.ToShortDateString()
                + DateTime.Now.ToShortTimeString();
            foreach (byte b in md5.ComputeHash(Encoding.Default.GetBytes(dateTime)))
            {
                suffix.Append(b.ToString("X"));
            }
            //Shorten the _tempDir Prefix
            for (int i = 0; i < suffix.Length; ++i)
            {
                suffix.Remove(i,1);
            }
                _tempDir = Environment.GetEnvironmentVariable("SystemDrive") + @"\"
                    + suffix.ToString();
        }
        protected override void EndCopyBehavior()
        {
            string zipFileName = _tempDir + @".zip";
            Somnus.IO.Compression.ZipHelper.Zip(_tempDir,zipFileName);
            Directory.Delete(_tempDir,true);
            FileInfo zipFile = new FileInfo(zipFileName);
            zipFile.MoveTo(_destDir + zipFile.Name);
        }
        public string ExcludedDiskNames
        {
            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    string updatedLabel = value;
                    string[] labels = updatedLabel.Split('|');
                    List<string> updatedLabelList = new List<string>(_includedDiskNamesArray);
                    foreach (string label in labels)
                    {
                        if (label.Length != 2 || !Regex.IsMatch(label, @"[C-Zc-z]:"))
                            throw new ArgumentException("Invalid DriveName");
                        updatedLabelList.Remove(label.ToUpper() + @"\");
                    }
                    if (updatedLabelList.Count == 0)
                        ExcludedDiskNames = "";
                    else
                        _includedDiskNamesArray = updatedLabelList.ToArray();
                }
                else if (String.Empty == value)
                {
                    List<string> nameList = new List<string>();
                    foreach (DriveInfo drive in DriveInfo.GetDrives())
                    {
                        if (drive.DriveType == DriveType.Fixed && drive.IsReady && drive.Name != @"C:\")
                            nameList.Add(drive.Name);
                    }
                    _includedDiskNamesArray = nameList.ToArray();
                }
            }

        }
        public bool IsIncludedOtherVolumes
        {
            set { _isIncludedOtherVolumes = value; }
            get { return _isIncludedOtherVolumes; }

        }
    }
}
